package com.lgmshare.component.widget.recyclerview;

import android.content.Context;
import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.StaggeredGridLayoutManager;

import com.lgmshare.component.annotation.LayoutRes;

import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.List;

public abstract class RecyclerViewHeaderFooterAdapter<T> extends RecyclerViewAdapter<T> {

    protected static final int VIEW_TYPE_HEADER_INDEX = 1;
    protected static final int VIEW_TYPE_DATA = 1024;
    protected static final int VIEW_TYPE_FOOTER_INDEX = 3096;

    protected List<Class<? extends HeaderFooterViewHolder>> mHeaderViewHolders;
    protected List<Class<? extends HeaderFooterViewHolder>> mFooterViewHolders;
    protected List<HeaderFooterValue> mHeaderValues;
    protected List<HeaderFooterValue> mFooterValues;

    protected OnHeaderClickListener mOnHeaderClickListener;
    protected OnFooterClickListener mOnFooterClickListener;

    public RecyclerViewHeaderFooterAdapter(Context context) {
        super(context);
    }

    /**
     * Same as RecyclerViewAdapter(Context,int) but with
     * some initialization data.
     *
     * @param context The context.
     * @param data    A new list is created out of this one to avoid mutable list
     */
    public RecyclerViewHeaderFooterAdapter(Context context, List<T> data) {
        super(context, data);
    }

    /**
     * 方法内已实现notify更新
     *
     * @param item
     */
    public void addItem(T item) {
        if (item != null) {
            this.mDataList.add(item);
        }
        this.notifyItemInserted(mDataList.size() + getHeaderCount());
    }

    /**
     * 方法内已实现notify更新
     *
     * @param position
     * @param item
     */
    @Override
    public void addItem(int position, T item) {
        if (item != null) {
            this.mDataList.add(position, item);
        }
        this.notifyItemInserted(position + getHeaderCount());
        //必须要重新刷新一遍数据，纠正position
        this.notifyItemRangeChanged(position + getHeaderCount(), mDataList.size() - position);
    }

    /**
     * 方法内已实现notify更新
     *
     * @param position
     */
    public void removeItem(int position) {
        this.mDataList.remove(position);
        this.notifyItemRemoved(position + getHeaderCount());
        //必须要重新刷新一遍数据，纠正position
        this.notifyItemRangeChanged(position + getHeaderCount(), mDataList.size() - position);
    }

    /**
     * 方法内已实现notify更新
     *
     * @param t
     */
    public void removeItem(T t) {
        int position = mDataList.indexOf(t);
        if (position >= 0) {
            this.mDataList.remove(t);
            this.notifyItemRemoved(position + getHeaderCount());
            //必须要重新刷新一遍数据，纠正position
            this.notifyItemRangeChanged(position + getHeaderCount(), mDataList.size() - position);
        }
    }

    public int getHeaderCount() {
        return mHeaderViewHolders == null ? 0 : mHeaderViewHolders.size();
    }

    public int getFooterCount() {
        return mFooterViewHolders == null ? 0 : mFooterViewHolders.size();
    }

    @Override
    public int getItemCount() {
        return getDataCount() + getHeaderCount() + getFooterCount();
    }

    //判断当前item类型
    @Override
    public int getItemViewType(int position) {
        if (position < getHeaderCount()) {
            //头部View
            return position;
        } else if (position < getHeaderCount() + getDataCount()) {
            //内容View
            return VIEW_TYPE_DATA;
        } else {
            //底部View
            return VIEW_TYPE_FOOTER_INDEX + (position - getHeaderCount() - getDataCount());
        }
    }

    @NonNull
    @Override
    public RecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        RecyclerViewHolder viewHolder = null;
        View itemView;
        if (viewType < getHeaderCount()) {
            // header
            Class<? extends HeaderFooterViewHolder> clazz = mHeaderViewHolders.get(viewType);
            LayoutRes layoutRes = clazz.getAnnotation(LayoutRes.class);
            itemView = getItemView(layoutRes.resId(), parent);
            try {
                Constructor constructor = clazz.getConstructor(Context.class, View.class);
                viewHolder = (HeaderFooterViewHolder) constructor.newInstance(mContext, itemView);
            } catch (Exception e) {
                e.printStackTrace();
                throw new RuntimeException("create header viewHolder failed");
            }
            RecyclerViewHolder finalViewHolder = viewHolder;
            itemView.setOnClickListener(v -> {
                if (mOnHeaderClickListener != null) {
                    mOnHeaderClickListener.onHeaderClick(finalViewHolder.getAdapterPosition());
                }
            });
        } else if (viewType == VIEW_TYPE_DATA) {
            // contact
            itemView = getItemView(onBindItemViewResId(), parent);
            viewHolder = new RecyclerViewHolder(mContext, itemView);
            bindItemViewClickListener(itemView, viewHolder);
        } else {
            // footer
            Class<? extends HeaderFooterViewHolder> clazz = mFooterViewHolders.get(viewType - VIEW_TYPE_FOOTER_INDEX);
            LayoutRes layoutRes = clazz.getAnnotation(LayoutRes.class);
            itemView = getItemView(layoutRes.resId(), parent);
            try {
                Constructor constructor = clazz.getConstructor(Context.class, View.class);
                viewHolder = (HeaderFooterViewHolder) constructor.newInstance(mContext, itemView);
            } catch (Exception e) {
                e.printStackTrace();
                throw new RuntimeException("create footer viewHolder failed");
            }
            RecyclerViewHolder finalViewHolder = viewHolder;
            itemView.setOnClickListener(v -> {
                if (mOnFooterClickListener != null) {
                    mOnFooterClickListener.onFooterClick(finalViewHolder.getAdapterPosition() - getHeaderCount() - getDataCount());
                }
            });
        }

        return viewHolder;
    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
        if (position < getHeaderCount()) {
            ((HeaderFooterViewHolder) holder).onBind(mHeaderValues.get(position));
        } else if (position < getHeaderCount() + getDataCount()) {
            int dataPosition = position - getHeaderCount();//list中数据index
            RecyclerViewHolder recyclerViewHolder = (RecyclerViewHolder) holder;
            recyclerViewHolder.setDataPosition(dataPosition);
            onBindItemViewData((RecyclerViewHolder) holder, getItem(dataPosition));
        } else {
            ((HeaderFooterViewHolder) holder).onBind(mFooterValues.get(position - getHeaderCount() - getDataCount()));
        }
    }

    @Override
    protected void bindItemViewClickListener(View view, final RecyclerViewHolder finalViewHolder) {
        if (mOnItemClickListener != null) {
            finalViewHolder.itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    int adapterPosition = finalViewHolder.getAdapterPosition() - getHeaderCount();
                    if (adapterPosition < 0) {
                        return;
                    }
                    mOnItemClickListener.onItemClick(v, adapterPosition);
                }
            });
        }
        if (mOnItemLongClickListener != null) {
            finalViewHolder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
                @Override
                public boolean onLongClick(View v) {
                    int adapterPosition = finalViewHolder.getAdapterPosition() - getHeaderCount();
                    if (adapterPosition < 0) {
                        return true;
                    }
                    //长按操作，如果返回false，onItemClick事件将会响应，返回true，则不会。
                    return mOnItemLongClickListener.onItemLongClick(v, adapterPosition);
                }
            });
        }
    }

    @Override
    protected void bindItemChildClickListener(View view, final RecyclerViewHolder finalViewHolder) {
        view.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int adapterPosition = finalViewHolder.getAdapterPosition() - getHeaderCount();
                if (adapterPosition < 0) {
                    return;
                }
                if (mChildClickListener != null) {
                    mChildClickListener.onItemChildClick(v, adapterPosition);
                }
            }
        });
    }

    @Override
    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
        super.onAttachedToRecyclerView(recyclerView);
        RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();
        if (manager instanceof GridLayoutManager) {
            final GridLayoutManager gridManager = ((GridLayoutManager) manager);
            gridManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
                @Override
                public int getSpanSize(int position) {
                    int type = getItemViewType(position);
                    if (isFullSpanType(type)) {
                        return gridManager.getSpanCount();
                    }
                    return 1;
                }
            });
        }
    }

    @Override
    public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) {
        super.onViewAttachedToWindow(holder);
        int type = holder.getItemViewType();
        if (isFullSpanType(type)) {
            ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
            if (lp != null && lp instanceof StaggeredGridLayoutManager.LayoutParams) {
                StaggeredGridLayoutManager.LayoutParams params = (StaggeredGridLayoutManager.LayoutParams) lp;
                params.setFullSpan(true);
            }
        }
    }

    /**
     * 是否是占满一行的类型
     *
     * @param type
     * @return
     */
    protected boolean isFullSpanType(int type) {
        return !(type == VIEW_TYPE_DATA);
    }

    public void addHeaderViewHolder(Class<? extends HeaderFooterViewHolder> clazz, HeaderFooterValue value) {
        if (mHeaderViewHolders == null) {
            mHeaderViewHolders = new ArrayList<>();
            mHeaderValues = new ArrayList<>();
        }
        mHeaderViewHolders.add(clazz);
        mHeaderValues.add(value);
    }

    public void removeHeader(int index) {
        mHeaderViewHolders.remove(index);
        mHeaderValues.remove(index);
        notifyItemRemoved(index);
    }

    public void updateHeader(int index, HeaderFooterValue value) {
        mHeaderValues.set(index, value);
        notifyItemChanged(index);
    }

    public void addFooterViewHolder(Class<? extends HeaderFooterViewHolder> clazz, HeaderFooterValue value) {
        if (mFooterViewHolders == null) {
            mFooterViewHolders = new ArrayList<>();
            mFooterValues = new ArrayList<>();
        }
        mFooterViewHolders.add(clazz);
        mFooterValues.add(value);
    }

    public void removeFooter(int index) {
        mFooterViewHolders.remove(index);
        mFooterValues.remove(index);
        notifyItemRemoved(getHeaderCount() + getDataCount() + index);
    }

    public void updateFooter(int index, HeaderFooterValue value) {
        mFooterValues.set(index, value);
        notifyItemChanged(getHeaderCount() + getDataCount() + index);
    }

    public void setOnHeaderClickListener(OnHeaderClickListener onHeaderClickListener) {
        this.mOnHeaderClickListener = onHeaderClickListener;
    }

    public void setOnFooterClickListener(OnFooterClickListener onFooterClickListener) {
        this.mOnFooterClickListener = onFooterClickListener;
    }

    public interface OnHeaderClickListener {
        void onHeaderClick(int position);
    }

    public interface OnFooterClickListener {
        void onFooterClick(int position);
    }
}
